package dk.au.cs.bdsi.composition.representations;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.StringWriter;
import java.util.LinkedList;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import dk.au.cs.bdsi.composition.activities.InvalidCompositionException;
import dk.au.cs.bdsi.composition.domain.Composition;



@XmlRootElement(name = "composition", namespace = Representation.SECREST_NAMESPACE)
public class CompositionRepresentation extends Representation {

    @XmlElement(name = "behaviour", namespace = Representation.SECREST_NAMESPACE)
    private String behaviour;

    @XmlElement(name = "status", namespace = Representation.SECREST_NAMESPACE)
    private String status;

	CompositionRepresentation(){}
	
    public static CompositionRepresentation fromXmlString(String xmlRepresentation) {
        try {
            JAXBContext context = JAXBContext.newInstance(CompositionRepresentation.class);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            return (CompositionRepresentation) unmarshaller.unmarshal(new ByteArrayInputStream(xmlRepresentation.getBytes()));
        } catch (Exception e) {
            throw new InvalidCompositionException(e);
        }
    }

    public static CompositionRepresentation createResponseOrderRepresentation(Composition comp, SecrestURI compUri) {
    	//SecrestURI secrestUri = new SecrestURI(compUri.getBaseUri() + "/composition/" + compUri.getId().toString());
        return new CompositionRepresentation(comp,new Link(Representation.SELF_REL_VALUE, compUri) );
/*    	if(order.getStatus() == OrderStatus.UNPAID) {
            return new OrderRepresentation(order, 
                    new Link(RELATIONS_URI + "cancel", orderUri), 
                    new Link(RELATIONS_URI + "payment", paymentUri), 
                    new Link(RELATIONS_URI + "update", orderUri),
                    new Link(Representation.SELF_REL_VALUE, orderUri));
        } else if(order.getStatus() == OrderStatus.PREPARING) {
            return new OrderRepresentation(order, new Link(Representation.SELF_REL_VALUE, orderUri));
        } else if(order.getStatus() == OrderStatus.READY) {
            return new OrderRepresentation(order, new Link(Representation.RELATIONS_URI + "reciept", UriExchange.receiptForPayment(paymentUri)));
        } else if(order.getStatus() == OrderStatus.TAKEN) {
            return new OrderRepresentation(order);            
        } else {
            throw new RuntimeException("Unknown Order Status");
        }
        */
    }

	public CompositionRepresentation(Composition comp, Link... links){
		try {
			this.behaviour=comp.getBehaviour();
			this.links=new LinkedList<Link>();
			for (Link l:links)
				this.links.add(l);
		} catch (Exception ex) {
            throw new InvalidCompositionException(ex);
        }
	}

    public String toString() {
        try {
            JAXBContext context = JAXBContext.newInstance(CompositionRepresentation.class);
            Marshaller marshaller = context.createMarshaller();
      
            SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
            Schema schema = sf.newSchema(new File("src/main/resources/Composition.xsd"));
       
            /*marshaller.setSchema(schema);
            marshaller.setEventHandler(new SysoutValidationEventHandler());
            marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new NamespacePrefixMapper() {
                @Override
                public String[] getPreDeclaredNamespaceUris() {
                    return new String[] { WellKnownNamespace.XML_SCHEMA_INSTANCE };
                }

                @Override
                public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
                    if (namespaceUri.equals(WellKnownNamespace.XML_SCHEMA_INSTANCE))
                        return "xsi";
                    if (namespaceUri.equals(WellKnownNamespace.XML_SCHEMA))
                        return "xs";
                    if (namespaceUri.equals(WellKnownNamespace.XML_MIME_URI))
                        return "xmime";
                    return suggestion;

                }
            }); */
            
            
            StringWriter stringWriter = new StringWriter();
            marshaller.marshal(this, stringWriter);
                        
            return stringWriter.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    static class SysoutValidationEventHandler implements ValidationEventHandler {
    	 
        public boolean handleEvent(ValidationEvent event) {
            System.out.println("\nEVENT");
            System.out.println("SEVERITY:  " + event.getSeverity());
            System.out.println("MESSAGE:  " + event.getMessage());
            System.out.println("LINKED EXCEPTION:  " + event.getLinkedException());
            System.out.println("LOCATOR");
            System.out.println("    LINE NUMBER:  " + event.getLocator().getLineNumber());
            System.out.println("    COLUMN NUMBER:  " + event.getLocator().getColumnNumber());
            System.out.println("    OFFSET:  " + event.getLocator().getOffset());
            System.out.println("    OBJECT:  " + event.getLocator().getObject());
            System.out.println("    NODE:  " + event.getLocator().getNode());
            System.out.println("    URL:  " + event.getLocator().getURL());
            return true;
        }
     
    }
	/*
 * public OrderRepresentation(Order order, Link... links) {
        try {
            this.location = order.getLocation();
            this.items = order.getItems();
            this.cost = order.calculateCost();
            this.status = order.getStatus();
            this.links = java.util.Arrays.asList(links);
        } catch (Exception ex) {
            throw new InvalidOrderException(ex);
        }
    }


 */
}
